package cn.wenhe9.novel.service.impl;

import cn.wenhe9.novel.auth.UserHolder;
import cn.wenhe9.novel.constant.*;
import cn.wenhe9.novel.domain.dto.*;
import cn.wenhe9.novel.domain.entity.book.BookComment;
import cn.wenhe9.novel.domain.entity.user.UserBookshelf;
import cn.wenhe9.novel.domain.entity.user.UserComment;
import cn.wenhe9.novel.domain.entity.user.UserFeedback;
import cn.wenhe9.novel.domain.entity.user.UserInfo;
import cn.wenhe9.novel.domain.vo.*;
import cn.wenhe9.novel.exception.NovelException;
import cn.wenhe9.novel.manager.*;
import cn.wenhe9.novel.mapper.UserBookshelfMapper;
import cn.wenhe9.novel.mapper.UserCommentMapper;
import cn.wenhe9.novel.mapper.UserFeedbackMapper;
import cn.wenhe9.novel.mapper.UserInfoMapper;
import cn.wenhe9.novel.result.PageResultDto;
import cn.wenhe9.novel.result.ResultResponse;
import cn.wenhe9.novel.service.UserService;
import cn.wenhe9.novel.util.JwtUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.apache.tomcat.util.buf.HexUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 会员模块 服务实现类
 *
 * @author DuJinliang
 * 2022/5/18
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private VerifyCodeManager verifyCodeManager;

    @Resource
    private UserFeedbackMapper userFeedbackMapper;

    @Resource
    private UserBookshelfMapper userBookshelfMapper;

    @Resource
    private UserCommentMapper userCommentMapper;

    @Resource
    private UserInfoCacheManager userInfoCacheManager;

    @Resource
    private UserFeedbackCacheManager userFeedbackCacheManager;

    @Resource
    private UserBookShelfCacheManager userBookShelfCacheManager;

    @Resource
    private UserReadHistoryCacheManager userReadHistoryCacheManager;

    @Resource
    private JwtUtils jwtUtils;

    @Override
    // dto vo do entity pojo
    public ResultResponse<UserRegisterDto> register(UserRegisterVo vo) {
        // 校验图形验证码是否正确
        if (!verifyCodeManager.imgVerifyCodeOk(vo.getSessionId(), vo.getVelCode())) {
            // 图形验证码校验失败
            throw new NovelException(ResultCodeEnum.USER_VERIFY_CODE_ERROR);
        }

        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConsts.UserInfoTable.COLUMN_USERNAME, vo.getUsername())
                .last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
        if (userInfoMapper.selectCount(queryWrapper) > 0) {
            // 手机号已注册
            throw new NovelException(ResultCodeEnum.USER_NAME_EXIST);
        }

        // 注册成功，保存用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setPassword(DigestUtils.md5DigestAsHex(vo.getPassword().getBytes(StandardCharsets.UTF_8)));
        userInfo.setUsername(vo.getUsername());
        userInfo.setNickName(vo.getUsername());
        userInfo.setCreateTime(LocalDateTime.now());
        userInfo.setUpdateTime(LocalDateTime.now());
        userInfo.setUserSex(0);
        userInfo.setSalt("0");
        userInfoMapper.insert(userInfo);

        // 删除验证码
        verifyCodeManager.removeImgVerifyCode(vo.getSessionId());

        // 生成JWT 并返回
        return ResultResponse.ok(
                UserRegisterDto.builder()
                        .token(jwtUtils.generateToken(userInfo.getId(), SystemConfigConsts.NOVEL_FRONT_KEY))
                        .uid(userInfo.getId())
                        .build()
        );
    }

    @Override
    public ResultResponse<UserLoginDto> login(UserLoginVo vo) {
        // 查询用户信息
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConsts.UserInfoTable.COLUMN_USERNAME, vo.getUsername())
                .last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if (Objects.isNull(userInfo)) {
            // 用户不存在
            throw new NovelException(ResultCodeEnum.USER_ACCOUNT_NOT_EXIST);
        }

        // 判断密码是否正确
        if (!Objects.equals(userInfo.getPassword()
                , DigestUtils.md5DigestAsHex(vo.getPassword().getBytes(StandardCharsets.UTF_8)))) {
            // 密码错误
            throw new NovelException(ResultCodeEnum.USER_PASSWORD_ERROR);
        }

        // 登录成功，生成JWT并返回
        return ResultResponse.ok(UserLoginDto.builder()
                .uid(userInfo.getId())
                .token(jwtUtils.generateToken(userInfo.getId(), SystemConfigConsts.NOVEL_FRONT_KEY))
                .nickName(userInfo.getNickName()).build());
    }

    @Override
    public ResultResponse<Void> saveFeedback(Long userId, String content) {
        return userFeedbackCacheManager.saveFeedback(userId, content);
    }

    @Override
    public ResultResponse<Void> updateUserInfo(Long userId, UserInfoUpdateVo vo) {
        userInfoCacheManager.updateUserInfo(userId, vo);
        return ResultResponse.ok();
    }

    @Override
    public ResultResponse<Void> deleteFeedback(Long userId, Long id) {
        QueryWrapper<UserFeedback> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConsts.CommonColumnEnum.ID.getName(), id)
                .eq(DatabaseConsts.UserFeedBackTable.COLUMN_USER_ID,userId);
        userFeedbackMapper.delete(queryWrapper);
        return ResultResponse.ok();
    }

    @Override
    public ResultResponse<Void> saveComment(UserCommentVo dto) {
        UserComment userComment = new UserComment();
        userComment.setBookId(dto.getBookId());
        userComment.setUserId(dto.getUserId());
        userComment.setCommentContent(dto.getCommentContent());
        userComment.setCreateTime(LocalDateTime.now());
        userComment.setUpdateTime(LocalDateTime.now());
        userCommentMapper.insert(userComment);
        return ResultResponse.ok();
    }

    @Override
    public ResultResponse<Integer> getBookshelfStatus(Long userId, String bookId) {
        QueryWrapper<UserBookshelf> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConsts.UserBookshelfTable.COLUMN_USER_ID, userId)
                .eq(DatabaseConsts.UserBookshelfTable.COLUMN_BOOK_ID, bookId);
        return ResultResponse.ok(
                userBookshelfMapper.selectCount(queryWrapper) > 0
                        ? CommonConsts.YES
                        : CommonConsts.NO
        );
    }

    @Override
    public ResultResponse<UserInfoDto> getUserInfo(Long userId) {
        UserInfoDto userInfoDto = userInfoCacheManager.getUser(userId);
        return ResultResponse.ok(userInfoDto);
    }

    @Override
    public void updatePassword(Long userId, UserPasswordUpdateVo vo) {
        String newPassword1 = vo.getNewPassword1();
        String newPassword2 = vo.getNewPassword2();

        if((!StringUtils.isEmpty(newPassword1) && newPassword1.equals(newPassword2))){
            ResultResponse.fail(ResultCodeEnum.TWO_PASSWORD_DIFF);
        }

        String oldPassword = vo.getOldPassword();
        userInfoCacheManager.updatePassword(userId, oldPassword, newPassword1);
    }

    @Override
    public PageResultDto<UserFeedbackDto> listFeedBack(Long userId, Long page, Long limit) {
        return userFeedbackCacheManager.listFeedback(userId, page, limit);
    }

    @Override
    public PageResultDto<UserBookShelfDto> listUserBookShelfByPage(Long userId, Long page, Long limit) {
        return userBookShelfCacheManager.listBookShelf(userId, page, limit);
    }

    @Override
    public void addToBookShelf(Long userId, Long bookId, Long preContentId) {
        userBookShelfCacheManager.addToBookShelf(userId, bookId, preContentId);
    }

    @Override
    public void removeFromBookShelf(Long userId, Long bookId) {
        userBookShelfCacheManager.removeFromBookShelf(userId, bookId);
    }

    @Override
    public void addReadHistory(Long userId, Long bookId, Long preContentId) {
        userReadHistoryCacheManager.addToReadHistory(userId, bookId, preContentId);
    }

    @Override
    public PageResultDto<UserReadHistoryDto> listReadHistoryByPage(Long userId, Long page, Long limit) {
        return userReadHistoryCacheManager.listReadHistory(userId, page, limit);
    }

    @Override
    public PageResultDto<UserCommentDto> listCommentByPage(Long userId, Long page, Long limit) {
        Page<UserCommentDto> commentDtoPage = userCommentMapper.queryCommentByPage(new Page(page, limit), userId);
        return PageResultDto.of(page, limit, commentDtoPage.getTotal(), commentDtoPage.getRecords());
    }
}
